home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / printing / magicfil.2 / magicfilter-1.2.tar / magicfilter-1.2 / magicfilter.c < prev    next >
C/C++ Source or Header  |  1996-03-17  |  24KB  |  1,042 lines

  1. /*
  2.  *  magicfilter.c
  3.  *
  4.  *  Copyright ⌐ 1993-96 H. Peter Anvin
  5.  *
  6.  *  "Magic" default filter for lpr/lpd which attempt to identify
  7.  *  the type of file and filter it accordingly
  8.  *
  9.  */
  10.  
  11. #include "magicfilter.h"
  12. #include <errno.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #ifdef HAVE_MEMORY_H
  16. #include <memory.h>
  17. #endif
  18. #ifdef HAVE_UNISTD_H
  19. #include <unistd.h>
  20. #endif
  21. #include <sys/fcntl.h>
  22. #include <sys/types.h>
  23. #ifdef HAVE_SYS_WAIT_H
  24. #include <sys/wait.h>
  25. #endif
  26.  
  27. char *inblock;            /* Block read */
  28. int inblock_size;        /* Bytes reserved for the inblock */
  29. int inblock_len;        /* Number of bytes read (<= inblock_size) */
  30. int done = 0;            /* Set to 1 if no more iterations */
  31. char *program;            /* Set to argv[0] in main() */
  32. char *config_file = NULL;    /* Configuration file */
  33. int debug_flag = 0;        /* If debugging */
  34.  
  35. /* What to call ourselves in case of failure */
  36. #define ERR_NAME                (config_file ? config_file : program)
  37.  
  38. extern const struct datatype dtypetab[]; /* Table of magic */
  39.  
  40. /* Location of the mailer */
  41. #ifndef NOMAIL
  42. #ifndef SENDMAIL
  43. #ifdef _PATH_SENDMAIL
  44. /* Path defined in paths.h */
  45. #define SENDMAIL _PATH_SENDMAIL
  46. #else
  47. #ifdef HAVE_SENDMAIL
  48. /* Path defined by autoconf */
  49. #define SENDMAIL PATH_SENDMAIL
  50. #endif
  51. #endif
  52. #endif
  53. #ifndef SENDMAIL
  54. /* We couldn't find a mailer anywhere -- disable mail */
  55. #define NOMAIL 1
  56. #endif
  57. #endif
  58.  
  59. /* Header of mail message */
  60. #ifndef NOMAIL
  61. const char *mailheader =    /* Header of complaint message */
  62. "To: %s\n\
  63. Subject: Rejected print job\n\
  64.  
  65. Your print job was automatically rejected as an invalid data type.\n\n";
  66. #endif
  67.  
  68. /* ------------------------------------------------------------------------- *
  69.  * Fudging of certain functions if we do not have them.  None of these
  70.  * are very good to use, but are better than nothing.
  71.  * ------------------------------------------------------------------------- */
  72.  
  73. #ifndef HAVE_DUP2
  74. int dup2(int fd1, int fd2)
  75.  
  76. #ifdef F_DUPFD
  77. {
  78.   close(fd2);
  79.   return fcntl(fildes, F_DUPFD, fd2);
  80. }
  81. #else
  82. {
  83.   int rtn;
  84.  
  85.   close(fd2);            /* Might return error if unused, is OK */
  86.   rtn = dup(fd1);
  87.  
  88.   if ( rtn >= 0 && rtn != fd2 )
  89.     {
  90.       fprintf(stderr, "%s: dup() trick failed -- aborting\n", ERR_NAME);
  91.       exit(1);
  92.     }
  93.  
  94.   return rtn;
  95. }
  96. #endif
  97.  
  98. #endif
  99.  
  100. #ifdef HAVE_TMPNAM
  101. /* If we don't have L_tmpnam, we can't use the provided tmpnam */
  102. #ifndef L_tmpnam
  103. #define tmpnam(X) my_tmpnam(X)
  104. #undef HAVE_TMPNAM
  105. #endif
  106. #endif
  107.  
  108. #ifndef HAVE_TMPNAM
  109. /*
  110.  * Lame implementation of tmpnam which works on most Unices
  111.  */
  112.  
  113. #define L_tmpnam (15+3*sizeof(pid_t))
  114.  
  115. char *tmpnam(char *buf)
  116. {
  117.   static char tmp_buf[L_tmpnam];
  118.   static int count = 0;
  119.  
  120.   if ( !buf ) buf = tmp_buf;
  121.  
  122.   sprintf(buf, "/tmp/_magf.%u.%02x", (unsigned int) getpid(), count++);
  123.   return buf;
  124. }
  125. #endif
  126.  
  127. /* ------------------------------------------------------------------------- *
  128.  *  run(command)
  129.  *
  130.  * Similar to system(), but always run a specified shell and does not
  131.  * fork.  We don't want to fork because we are creating a pipe, anyway.
  132.  *
  133.  * The shell is defined in SYSSHELL and is called as
  134.  * ``<SYSSHELL> -c command_line''
  135.  * ------------------------------------------------------------------------- */
  136.  
  137. #ifndef SYSSHELL
  138. #ifdef _PATH_BSHELL
  139. #define SYSSHELL _PATH_BSHELL
  140. #else
  141. #define SYSSHELL "/bin/sh"
  142. #endif
  143. #endif
  144. #ifndef SHELLFLAG
  145. #define SHELLFLAG "-c"
  146. #endif
  147.  
  148. void run(char *command)
  149. {
  150.   execl(SYSSHELL,SYSSHELL,SHELLFLAG,command,(char *)NULL);
  151.   exit(255);            /* If we get here, the exec failed */
  152. }
  153.  
  154.  
  155. /* ------------------------------------------------------------------------- *
  156.  *  fork_daemon()
  157.  *
  158.  * Fork a process that doesn't have to be wait'ed on.  This it done by
  159.  * forking *twice* and orphanning the grandchild process, leaving it
  160.  * adopted by init.  Do a reasonable job of propagating errors.
  161.  *
  162.  * Returns 0 for the child and 1 for the parent if OK; otherwise -1.
  163.  * (The reason the parent returns 1 is that is *doesn't know* the pid of
  164.  * the spawned child process.)
  165.  * ------------------------------------------------------------------------- */
  166.  
  167. /* This is for non-POSIX compliant systems */
  168. #ifndef WEXITSTATUS
  169. #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
  170. #endif
  171. #ifndef WIFEXITED
  172. #define WIFEXITED(stat_val) (((stat_val) & 0xff) == 0)
  173. #endif
  174.  
  175. #ifndef HAVE_WAITPID
  176. /* We don't have waitpid(), we have to emulate it */
  177. #ifdef HAVE_WAIT4
  178. /* With wait4() we should be set */
  179. #define waitpid(p,s,o) wait4(p, s, o, NULL)
  180. #else
  181. /* This is a feeble implementation using wait(); it doesn't implement
  182.    the full waitpid() semantics, but should be close enough for
  183.    what we need.  Use with caution. */
  184. pid_t waitpid(pid_t pid, int *status, int options)
  185. {
  186.   pid_t retval;
  187.   do
  188.     retval = wait(status);
  189.   while ( retval > 0 && retval != pid );
  190.   return retval;
  191. }
  192. #endif
  193. #endif
  194.  
  195. int fork_daemon(void)
  196. {
  197.   pid_t pid;
  198.   int status;
  199.  
  200.   pid = fork();
  201.   if ( pid < 0 )
  202.     return -1;            /* Error on first fork */
  203.   else if ( pid == 0 )
  204.     {
  205.       pid = fork();
  206.       if ( pid < 0 )
  207.     _exit(errno);
  208.       else if ( pid == 0 )
  209.     return 0;        /* Child process */
  210.       else
  211.     _exit(0);
  212.     }
  213.   else
  214.     {
  215.       waitpid(pid,&status,0);
  216.       if (status)        /* Did we return error? */
  217.     {
  218.       errno = WIFEXITED(status) ? WEXITSTATUS(status) : EINTR;
  219.       return -1;
  220.     }
  221.       return 1;            /* Parent process */
  222.     }
  223. }
  224.  
  225. /* ------------------------------------------------------------------------- *
  226.  *  cat(file)
  227.  *  act_cat(opt_string)
  228.  *
  229.  * Feed the input to a specified file without any processing whatsoever.
  230.  *
  231.  * act_cat() is the action; it will attempt to extract a prefix and suffix
  232.  * string from the included option string as well.
  233.  * ------------------------------------------------------------------------- */
  234.  
  235. void cat(FILE *f)
  236. {
  237.   if ( inblock_len > 0 )
  238.     fwrite(inblock,1,inblock_len,f);
  239.  
  240.   while( ( inblock_len = fread(inblock,1,inblock_size,stdin) ) > 0 )
  241.     {
  242.       fwrite(inblock,1,inblock_len,f);
  243.     }
  244. }
  245.  
  246. typedef void datafunc(FILE *);
  247. void do_prefix_suffix(char *opt_str, datafunc *convfunc, FILE *f)
  248. {
  249.   char *p, *prefix, *suffix = NULL;
  250.   int n;
  251.  
  252.   if ( (n = getmagic(opt_str,&p,NULL,NO_WILD)) >= 0 )
  253.     {
  254.       if ( n > 0 )
  255.     {
  256.       if ( !(prefix = malloc(n)) )
  257.         {
  258.           fprintf(stderr, "%s: Out of memory\n", ERR_NAME);
  259.           exit(1);
  260.         }
  261.       getmagic(opt_str,&p,prefix,NO_WILD);
  262.       fwrite(prefix,1,n,f); /* Write prefix string */
  263.       free(prefix);
  264.     }
  265.       if ( (n = getmagic(p,NULL,NULL,NO_WILD)) > 0 )
  266.     {
  267.       if ( !(suffix = malloc(n)) )
  268.         {
  269.           fprintf(stderr, "%s: Out of memory\n", ERR_NAME);
  270.           exit(1);
  271.         }
  272.       getmagic(p,NULL,suffix,NO_WILD);
  273.     }
  274.     }
  275.   
  276.   convfunc(f);
  277.  
  278.   if ( suffix )
  279.     {
  280.       fwrite(suffix,1,n,f);
  281.       free(suffix);
  282.     }
  283. }
  284.  
  285. void act_cat(char *opt_str)
  286. {
  287.   if ( debug_flag )
  288.     fprintf(stderr, "cat %s\n", opt_str);
  289.   
  290.   do_prefix_suffix(opt_str, cat, stdout);
  291.   done = 1;
  292. }
  293.  
  294. /* ------------------------------------------------------------------------- *
  295.  *  act_addcr()
  296.  *
  297.  * Feed the input to the output, substituting:
  298.  *    \n -> \r\n     \f -> \r\f
  299.  *
  300.  * It also adds \r\f at the end of the file.
  301.  * 
  302.  * Used for printers which need CR's at line endings.  Note that if your
  303.  * printer supports a different character set (say Roman-8) than your host
  304.  * (say Latin-1) you may be better off using ACT_FILTER and a translating
  305.  * filter such as "lpchar".
  306.  * ------------------------------------------------------------------------- */
  307.  
  308. void addcr(FILE *f)
  309. {
  310.   char *p;
  311.   int i;
  312.  
  313.   do
  314.     {
  315.       for ( i = inblock_len, p = inblock ; i ; i--, p++ )
  316.     {
  317.       switch ( *p )
  318.         {
  319.         case '\n':
  320.         case '\f':
  321.           putc('\r', f);
  322.           /* Fall through */
  323.  
  324.         default:
  325.           putc(*p, f);
  326.           break;
  327.         }
  328.     }
  329.     
  330.       inblock_len = fread(inblock, 1, inblock_size, stdin);
  331.     }
  332.   while ( inblock_len > 0 );
  333.  
  334.   putc('\r', f);
  335.   putc('\f', f);
  336. }
  337.  
  338.  
  339. void act_addcr(char *opt_str)
  340. {
  341.   if ( debug_flag )
  342.     fprintf(stderr, "text %s\n", opt_str);
  343.  
  344.   do_prefix_suffix(opt_str, addcr, stdout);
  345.   done = 1;
  346. }
  347.  
  348. /* ------------------------------------------------------------------------- *
  349.  *  act_ps()
  350.  *
  351.  * Like act_addcr() but add a Ctrl-D to the end (PostScript End of Job).
  352.  * Keeps the printer from running two jobs together.  nenscript in
  353.  * particular is bad with this.
  354.  * ------------------------------------------------------------------------- */
  355.  
  356. void act_ps(void)
  357. {
  358.   if ( debug_flag )
  359.     fprintf(stderr, "postscript\n");
  360.   
  361.   addcr(stdout);
  362.   putchar('\4');
  363.   done = 1;
  364. }
  365.  
  366.  
  367. /* ------------------------------------------------------------------------- *
  368.  *  act_drop()
  369.  *
  370.  * Just sets the done flag.
  371.  * ------------------------------------------------------------------------- */
  372.  
  373. void act_drop(void)
  374. {
  375.   if ( debug_flag )
  376.     fprintf(stderr, "ignore\n");
  377.  
  378.   done = 1;
  379. }
  380.  
  381.  
  382. /* ------------------------------------------------------------------------- *
  383.  *  act_reject(message,user,host)
  384.  *
  385.  * Sends a rejection message to the user.  A bad file (such as an executable
  386.  * binary) was encountered.
  387.  * ------------------------------------------------------------------------- */
  388.  
  389. #ifndef NOMAIL
  390. void act_reject(char *message, char *user, char *host)
  391. {
  392.   int fildes[2];        /* File descriptors for pipe */
  393.   pid_t pid;
  394.   FILE *msg;            /* Outgoing pipe */
  395.   char address[BUFSIZ];        /* Buffer to create address */
  396.   int status;
  397.  
  398.   if ( debug_flag )
  399.     fprintf(stderr, "reject %s\n", message);
  400.  
  401. #ifdef BANG_ADDRESS
  402.   sprintf(address,"%s!%s", host, user);
  403. #else
  404.   sprintf(address,"%s@%s", user, host);
  405. #endif
  406.  
  407.   if ( pipe(fildes) )
  408.     {
  409.       perror(ERR_NAME);
  410.       exit(1);
  411.     }
  412.  
  413.   pid = fork();
  414.  
  415.   if ( pid < 0 )        /* Fork failed */
  416.     {
  417.       perror(ERR_NAME);
  418.       exit(1);
  419.     }
  420.   else if ( pid == 0 )        /* Child process */
  421.     {
  422.       close(fildes[1]);
  423.       dup2(fildes[0],fileno(stdin)); /* Redirect stdin */
  424.       execl(SENDMAIL,SENDMAIL,address,(char *) NULL);
  425.       exit(255);        /* Exec failed */
  426.     }
  427.   else                /* Parent process */
  428.     {
  429.       close(fildes[0]);
  430.       msg = fdopen(fildes[1],"wb"); /* Make pipe file pointer */
  431.  
  432.       fprintf(msg, mailheader, address);
  433.       fprintf(msg, "%s\n", message);
  434.       fclose(msg);
  435.  
  436.       waitpid(pid,&status,0);
  437.  
  438.       if ( status )
  439.     {
  440.       fprintf(stderr, "%s: %s failed\n", ERR_NAME, SENDMAIL);
  441.     }
  442.     }
  443.  
  444.   done = 1;
  445. }
  446. #else
  447. #define act_reject(MSG,USR,HST) act_drop()
  448. #endif    
  449.  
  450.  
  451. /* ------------------------------------------------------------------------- *
  452.  *  act_filter(command)
  453.  * 
  454.  * Set up a pipe and filter the input through that command.  Output goes
  455.  * to stdout.
  456.  * ------------------------------------------------------------------------- */
  457.  
  458. void act_filter(char *command)
  459. {
  460.   int fildes[2];        /* File descriptors for pipe */
  461.   FILE *out;            /* Output file pointer */
  462.   pid_t pid;            /* Child process ID */
  463.   int status;
  464.  
  465.   if ( debug_flag )
  466.     fprintf(stderr, "filter %s\n", command);
  467.  
  468.   if ( pipe(fildes) )
  469.     {
  470.       perror(ERR_NAME);
  471.       exit(1);
  472.     }
  473.  
  474.   pid = fork();
  475.  
  476.   if ( pid < 0 )        /* Fork failed */
  477.     {
  478.       perror(ERR_NAME);
  479.       exit(1);
  480.     }
  481.   else if ( pid == 0 )        /* Child process */
  482.     {
  483.       close(fildes[1]);
  484.       dup2(fildes[0],fileno(stdin)); /* Redirect stdin */
  485.       run(command);
  486.     }
  487.   else                /* Parent process */
  488.     {
  489.       close(fildes[0]);
  490.       out = fdopen(fildes[1],"wb"); /* Make pipe file pointer */
  491.       cat(out);            /* Send output into pipe */
  492.       fclose(out);
  493.  
  494.       waitpid(pid,&status,0);
  495.  
  496.       if ( status )
  497.     {
  498.       fprintf(stderr, "%s: %s failed\n", ERR_NAME, command);
  499.     }
  500.     }
  501.  
  502.   done = 1;
  503. }
  504.  
  505. /* ------------------------------------------------------------------------- *
  506.  *  act_ffilter(command)
  507.  * 
  508.  * Create a temp file; then filter the temp file through that command.
  509.  * Output goes to stdout.
  510.  * ------------------------------------------------------------------------- */
  511.  
  512. void act_ffilter(char *command)
  513. {
  514.   static char tmpbuf[L_tmpnam+6] = "FILE=";
  515.   FILE *out;            /* Output file pointer */
  516.   int outfd;            /* Output file descriptor */
  517.   pid_t pid;            /* Child process ID */
  518.   int status;
  519.  
  520.   if ( debug_flag )
  521.     fprintf(stderr, "ffilter %s\n", command);
  522.  
  523.   if ( !tmpnam(tmpbuf+5) || !(out = fopen(tmpbuf+5, "wb")) )
  524.     {
  525.       perror(ERR_NAME);
  526.       exit(1);
  527.     }
  528.  
  529.   cat(out);            /* Send output to temp file */
  530.   fclose(out);
  531.  
  532.   pid = fork();
  533.  
  534.   if ( pid < 0 )        /* Fork failed */
  535.     {
  536.       perror(ERR_NAME);
  537.       exit(1);
  538.     }
  539.   else if ( pid == 0 )        /* Child process */
  540.     {
  541.       putenv(tmpbuf);        /* Store name in $FILE */
  542.       outfd = open(tmpbuf+5, O_RDONLY);
  543.       dup2(outfd,fileno(stdin)); /* Redirect stdin */
  544.       run(command);
  545.     }
  546.   else                /* Parent process */
  547.     {
  548.       waitpid(pid,&status,0);    /* Wait for process to finish */
  549.  
  550.       if ( status )
  551.     {
  552.       fprintf(stderr, "%s: %s failed\n", ERR_NAME, command);
  553.     }
  554.  
  555.       unlink(tmpbuf+5);        /* Remove temp file */
  556.     }
  557.  
  558.   done = 1;
  559. }
  560.  
  561. /* ------------------------------------------------------------------------- *
  562.  *  act_pipethru(command)
  563.  *
  564.  * Pipes the output through a given command, creating a second pipe to
  565.  * fetch the input for re-processing.
  566.  *
  567.  * This is done the "proper" way by creating a sender and a receiver process
  568.  * around the filter process; who knows what the OS does if we overflow a
  569.  * pipe.
  570.  * ------------------------------------------------------------------------- */
  571.  
  572. void act_pipethru(char *command)
  573. {
  574.   int inpipefd[2];        /* File descriptors for input pipe */
  575.   int outpipefd[2];        /* File descriptors for output pipe */
  576.   FILE *out;            /* Output file pointer */
  577.   pid_t pid, xpid, wpid;
  578.   int null;            /* /dev/null */
  579.   int status;            /* Process exit status */
  580.  
  581.   if ( debug_flag )
  582.     fprintf(stderr, "pipe %s\n", command);
  583.  
  584.   if ( pipe(inpipefd) || pipe(outpipefd) )
  585.     {
  586.       perror(ERR_NAME);
  587.       exit(1);
  588.     }
  589.  
  590.   xpid = fork_daemon();
  591.   
  592.   if ( xpid < 0 )
  593.     {
  594.       perror(ERR_NAME);
  595.       exit(1);
  596.     }
  597.   else if ( xpid == 0 )
  598.     {
  599.        close(outpipefd[0]);
  600.  
  601.        pid = fork();
  602.  
  603.        if ( pid < 0 )        /* Fork failed */
  604.      {
  605.        perror(ERR_NAME);
  606.        exit(1);
  607.      }
  608.        else if ( pid == 0 )        /* Child process */
  609.      {
  610.        close(inpipefd[1]);
  611.        dup2(inpipefd[0],fileno(stdin));
  612.        dup2(outpipefd[1],fileno(stdout)); /* Redirect stdout */
  613.        run(command);
  614.      }
  615.        else
  616.      {
  617.        /* Writing process */
  618.  
  619.        close(inpipefd[0]);
  620.        close(outpipefd[1]);
  621.        
  622.        out = fdopen(inpipefd[1],"wb");
  623.        cat(out);        /* Send output into pipe */
  624.        fclose(out);
  625.        
  626.        /* Wait for filter to exit */
  627.  
  628.        if ( waitpid(pid,&status,0) < 0 )
  629.          perror("waitpid");
  630.        
  631.        /* If status > 0 we should probably do something, but it is
  632.           difficult to know what we can do at this stage */
  633.        
  634.        exit(0);
  635.      }
  636.      }
  637.   else
  638.     {
  639.       /* Reading process */
  640.       
  641.       close(inpipefd[0]);
  642.       close(outpipefd[1]);
  643.       close(inpipefd[1]);
  644.       
  645.       /* Flush the stdin buffer */
  646.       null = open("/dev/null", O_RDONLY);
  647.       dup2(null, fileno(stdin));
  648.       close(null);
  649.       while ( fread(inblock,1,inblock_size,stdin) > 0 );
  650.       
  651.       if ( dup2(outpipefd[0],fileno(stdin)) < 0 )
  652.     {
  653.       perror("dup2");
  654.       exit(1);
  655.     } /* Redirect stdin */
  656.       
  657.       close(outpipefd[0]);
  658.       
  659.       rewind(stdin);
  660.       inblock_len = fread(inblock,1,inblock_size,stdin);
  661.     }
  662. }
  663.  
  664.  
  665. /* ------------------------------------------------------------------------- *
  666.  *  act_fpipe(command)
  667.  *
  668.  * Creates a temp file and sends the output through a given command,
  669.  * creating a pipe to fetch the input for re-processing.
  670.  * ------------------------------------------------------------------------- */
  671.  
  672. void act_fpipe(char *command)
  673. {
  674.   static char tmpbuf[L_tmpnam+6] = "FILE=";
  675.   int outpipefd[2];        /* File descriptors for output pipe */
  676.   FILE *out;            /* Output file pointer */
  677.   int outfd;            /* Output file descriptor */
  678.   pid_t pid, xpid, wpid;
  679.   int null;            /* /dev/null */
  680.   int status;            /* Exit status */
  681.  
  682.   if ( debug_flag )
  683.     fprintf(stderr, "fpipe %s\n", command);
  684.  
  685.   if ( !tmpnam(tmpbuf+5) || !(out = fopen(tmpbuf+5,"w+b")) || pipe(outpipefd) )
  686.     {
  687. #if DEBUG > 2
  688.       fprintf(stderr, "TMPBUF: %s\n", tmpbuf);
  689. #endif
  690.       perror(ERR_NAME);
  691.       exit(1);
  692.     }
  693.  
  694.   cat(out);            /* Write output to file */
  695.   fclose(out);
  696.  
  697.   xpid = fork_daemon();
  698.   
  699.   if ( xpid < 0 )
  700.     {
  701.       perror(ERR_NAME);
  702.       exit(1);
  703.     }
  704.   else if ( xpid == 0 )
  705.     {
  706.       close(outpipefd[0]);
  707.       
  708.       pid = fork();
  709.       
  710.       if ( pid < 0 )        /* Fork failed */
  711.     {
  712.       perror(ERR_NAME);
  713.       exit(1);
  714.     }
  715.       else if ( pid == 0 )        /* Child process */
  716.     {
  717.       putenv(tmpbuf);        /* Store name in $FILE */
  718.       outfd = open(tmpbuf+5, O_RDONLY);
  719.       dup2(outfd,fileno(stdin)); /* Redirect stdin */
  720.       dup2(outpipefd[1],fileno(stdout)); /* Redirect stdout */
  721.       run(command);
  722.     }
  723.       else                /* Parent process */
  724.     {
  725.       close(outpipefd[1]);
  726.       
  727.       /* Wait for filter to finish and then remove temp file */
  728.  
  729.       if ( waitpid(pid,&status,0) < 0 )
  730.         perror("waitpid");
  731.       
  732.       /* If status > 0 we should probably do something, but it is
  733.          difficult to know what we can do at this stage */
  734.       
  735.       unlink(tmpbuf+5);
  736.       exit(0);
  737.     }
  738.     }
  739.   else
  740.     {
  741.       close(outpipefd[1]);
  742.       
  743.       /* Reading process */
  744.       
  745.       /* Flush the stdin buffer */
  746.       null = open("/dev/null", O_RDONLY);
  747.       dup2(null, fileno(stdin));
  748.       close(null);
  749.       while ( fread(inblock,1,inblock_size,stdin) > 0 );
  750.       
  751.       if ( dup2(outpipefd[0],fileno(stdin)) < 0 )
  752.     {
  753.       perror("dup2");
  754.       exit(1);
  755.     } /* Redirect stdin */
  756.       
  757.       close(outpipefd[0]);
  758.       
  759.       rewind(stdin);
  760.       inblock_len = fread(inblock,1,inblock_size,stdin);
  761.     }
  762. }
  763.  
  764.  
  765. /* ------------------------------------------------------------------------- *
  766.  *  matches(block, pattern, mask, length)
  767.  *
  768.  *  Returns nonzero if block matches pattern.
  769.  * ------------------------------------------------------------------------- */
  770.  
  771. int matches(char *block, char *pattern, char *mask, int length)
  772. {
  773.   int i;
  774.   char *p, *q, *m;
  775.  
  776.   q = block;
  777.   p = pattern;
  778.   m = mask;
  779.  
  780.   for ( i = length ; i ; i-- )
  781.     {
  782.       if ( (*p ^ *q) & *m )
  783.     return 0;
  784.       q++; p++; m++;
  785.     }
  786.  
  787. #if DEBUG > 3
  788.   fprintf(stderr,"Pattern: ");
  789.   for ( i = 0 ; i < length ; i++ )
  790.     {
  791.       fprintf(stderr,"%03o ", (unsigned char) block[i]);
  792.     }
  793.   fprintf(stderr,"\nMatches: ");
  794.   for ( i = 0 ; i < length ; i++ )
  795.     {
  796.       if ( mask[i] )
  797.     fprintf(stderr,"%03o ", (unsigned char) pattern[i]);
  798.       else
  799.     fprintf(stderr,"??? ");
  800.     }
  801.   fprintf(stderr,"\n");
  802. #endif
  803.  
  804.   return 1;
  805. }
  806.  
  807. /* ------------------------------------------------------------------------- *
  808.  *  envset(var,value)
  809.  * 
  810.  * Inserts a key value into the environment
  811.  * ------------------------------------------------------------------------- */
  812.  
  813. void envset(char *var, char *value)
  814. {
  815.   char *buf;
  816.  
  817.   if ( !(buf = malloc(strlen(var)+strlen(value)+2)) )
  818.     {
  819.       fprintf(stderr, "%s: out of memory\n", ERR_NAME);
  820.       exit(1);
  821.     }
  822.   sprintf(buf, "%s=%s", var, value);
  823.   if ( putenv(buf) )
  824.     {
  825.       perror(ERR_NAME);
  826.       exit(1);
  827.     }
  828.   if ( debug_flag )
  829.     fprintf(stderr, "%s\n", buf);
  830. }
  831.  
  832. /* ------------------------------------------------------------------------- *
  833.  *  main(argc,argv)
  834.  * 
  835.  * Analyze the input data and choose an appropriate way to handle it.
  836.  * ------------------------------------------------------------------------- */
  837.  
  838. main(int argc, char *argv[])
  839. {
  840.   int do_cat = 0;        /* True if -c option */
  841.   int i;
  842.   const struct datatype *dtab;    /* Data type table */
  843.   const struct datatype *dt;    /* Data type searched */
  844.   char *user = "unknown";    /* User name */
  845.   char *host = "unknown";    /* Host name */
  846.  
  847.   program = argv[0];        /* Make available for error messages */
  848.  
  849.   if ( argc < 2 )
  850.     {
  851.       fprintf(stderr, "%s: No configuration file specified\n", program);
  852.       exit(1);
  853.     }
  854.  
  855.   /* Clear these strings from environment; if we have unsetenv use it,
  856.      otherwise set to blank strings */
  857.  
  858. #ifdef HAVE_UNSETENV
  859.   unsetenv("LPUSER");
  860.   unsetenv("LPHOST");
  861.   unsetenv("LPJOB");
  862.   unsetenv("FILE");
  863.   unsetenv("PRINTER");
  864.   unsetenv("LPFORMAT");
  865.   unsetenv("LPCLASS");
  866.   unsetenv("LPACCT");
  867.   unsetenv("LPCOPIES");
  868.   unsetenv("LPQUEUE");
  869.   unsetenv("ZOPT");
  870.   unsetenv("BANNERNAME");
  871. #else
  872.   putenv("LPUSER=");
  873.   putenv("LPHOST=");
  874.   putenv("LPJOB=");
  875.   putenv("FILE=");
  876.   putenv("PRINTER=");
  877.   putenv("LPFORMAT=");
  878.   putenv("LPCLASS=");
  879.   putenv("LPACCT=");
  880.   putenv("LPCOPIES=");
  881.   putenv("LPQUEUE=");
  882.   putenv("ZOPT=");
  883.   putenv("BANNERNAME=");
  884. #endif
  885.   putenv("LPINDENT=0");        /* Default to zero */
  886.  
  887.   for ( i = 1 ; i < argc ; i++ ) /* Options passed by lpd */
  888.     {
  889.       if ( argv[i][0] == '-' )
  890.     {
  891.       if ( strcmp(argv[i],"-c") == 0 )
  892.         do_cat = 1;
  893.       else if ( strncmp(argv[i],"-n",2) == 0 )
  894.         {
  895.           user = (argv[i][2] || i == argc-1) ? argv[i]+2 : argv[++i];
  896.           envset("LPUSER", user);
  897.         }
  898.       else if ( strncmp(argv[i],"-h",2) == 0 )
  899.         {
  900.           host = (argv[i][2] || i == argc-1) ? argv[i]+2 : argv[++i];
  901.           envset("LPHOST", host);
  902.         }
  903.       else if ( strncmp(argv[i],"-i",2) == 0 )
  904.         envset("LPINDENT", argv[i]+2);
  905.       else if ( strncmp(argv[i],"-C",2) == 0 )
  906.         envset("LPCLASS", argv[i]+2);
  907.       else if ( strncmp(argv[i],"-F",2) == 0 )
  908.         envset("LPFORMAT", argv[i]+2);
  909.       else if ( strncmp(argv[i],"-J",2) == 0 )
  910.         envset("LPJOB", argv[i]+2);
  911.       else if ( strncmp(argv[i],"-K",2) == 0 )
  912.         envset("LPCOPIES", argv[i]+2);
  913.       else if ( strncmp(argv[i],"-L",2) == 0 )
  914.         envset("BANNERNAME", argv[i]+2);
  915.       else if ( strncmp(argv[i],"-P",2) == 0 )
  916.         envset("PRINTER", argv[i]+2);
  917.       else if ( strncmp(argv[i],"-Q",2) == 0 )
  918.         envset("LPQUEUE", argv[i]+2);
  919.       else if ( strncmp(argv[i],"-R",2) == 0 )
  920.         envset("LPACCT", argv[i]+2);
  921.       else if ( strncmp(argv[i],"-Z",2) == 0 )
  922.         envset("ZOPT", argv[i]+2);
  923.       else if ( strcmp(argv[i], "--debug") == 0 )
  924.         debug_flag = 1;
  925.       /* Ignore other options passed by lpd */
  926.     }
  927.       else if ( !config_file )
  928.     config_file = argv[i];
  929.     }
  930.  
  931.   umask(077);            /* Protect the user's privacy */
  932.  
  933.   if ( do_cat )            /* Literal flag: skip config file */
  934.     {
  935.       if ( debug_flag )
  936.     fprintf(stderr, "(literal)\n");
  937.       inblock_size = BUFSIZ;
  938.     }
  939.   else
  940.     {
  941.       dtab = load_config(config_file, &i); /* Load configuration file */
  942.       if ( !dtab ) exit(1);    /* load_config does the error message */
  943.       /* Round up to nearest multiple of BUFSIZ, for efficiency */
  944.       inblock_size = ((i+BUFSIZ-1)/BUFSIZ)*BUFSIZ;
  945.     }
  946.  
  947.   if ( !(inblock = malloc(inblock_size)) )
  948.     {
  949.       fprintf(stderr, "%s: Out of memory\n", ERR_NAME);
  950.       exit(1);
  951.     }
  952.   
  953.   inblock_len = fread(inblock,1,inblock_size,stdin);
  954.       
  955.   if ( do_cat )            /* Literal flag -> always ACT_CAT */
  956.     {
  957.       cat(stdout);
  958.       done = 1;
  959.     }
  960.   else
  961.     {
  962.       while ( !done && inblock_len > 0 )
  963.     {
  964.       dt = dtab;        /* Head of linked list */
  965.       while ( dt )
  966.         {
  967.           if ( dt->length < 1 ||
  968.           matches(inblock+dt->offset,dt->magic,dt->mask,dt->length) )
  969.         break;
  970.           
  971.           dt = dt->next;
  972.         }
  973.       
  974.       if ( !dt )
  975.         {
  976.           fprintf(stderr, "%s: Unknown type data and no default; \
  977. job sent by %s@%s)\n", ERR_NAME, user, host);
  978.           exit(1);
  979.         }
  980.       
  981.       /* Now dt should point to the proper data type record to use */
  982.       
  983.       switch( dt->action )
  984.         {
  985.         case ACT_CAT:
  986.           act_cat(dt->command);
  987.           break;
  988.           
  989.         case ACT_DROP:
  990.           act_drop();
  991.           break;
  992.           
  993.         case ACT_REJECT:
  994.           act_reject(dt->command, user, host);
  995.           break;
  996.           
  997.         case ACT_FILTER:
  998.           act_filter(dt->command);
  999.           break;
  1000.           
  1001.         case ACT_PIPETHRU:
  1002.           act_pipethru(dt->command);
  1003.           break;
  1004.           
  1005.         case ACT_ADDCR:
  1006.           act_addcr(dt->command);
  1007.           break;
  1008.  
  1009.         case ACT_PS:
  1010.           act_ps();
  1011.           break;
  1012.  
  1013.         case ACT_FFILTER:
  1014.           act_ffilter(dt->command);
  1015.           break;
  1016.  
  1017.         case ACT_FPIPE:
  1018.           act_fpipe(dt->command);
  1019.           break;
  1020.  
  1021.         default:
  1022.           fprintf(stderr, "%s(%s): Internal error - invalid parse\n\
  1023. Please mail your configuration file to <Peter.Anvin@linux.org>\n",
  1024.               program, config_file);
  1025.           return 1;
  1026.         }
  1027.     }
  1028.  
  1029. #ifdef REJECT_EMPTY
  1030.       if ( !done )
  1031.     {
  1032.       /* Send a message to the user informing that his/her print job
  1033.          ended up empty */
  1034.  
  1035.       act_reject(REJECT_EMPTY, user, host);
  1036.     }
  1037. #endif
  1038.     }
  1039.  
  1040.   return 0;            /* Error */
  1041. }
  1042.